home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume20 / index-db / part01 next >
Encoding:
Internet Message Format  |  1989-10-23  |  54.3 KB

  1. Subject:  v20i056:  Maintain multiple databases of textual data, Part01/02
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dave Curry <davy@riacs.edu>
  7. Posting-number: Volume 20, Issue 56
  8. Archive-name: index-db/part01
  9.  
  10. This is index, Version 1.0.
  11.  
  12. Index allows you to maintain multiple databases of textual information,
  13. each with a different format.  With each database, index allows you to:
  14.     - add entries
  15.     - delete entries
  16.     - edit existing entries
  17.     - search for entries using full regular expressions
  18.     - control what parts of an entry are searched
  19.     - print out entries matching a pattern
  20.     - run all or part of the database through an arbitrary
  21.       formatting program
  22.  
  23. The databases index maintains are stored as simple lines of text.  Each
  24. field of an entry is a line of text, and each entry in the database is
  25. made up of a fixed number of lines.  For each database, you tell index
  26. what each field's (line's) name is.  You can have multiple-line fields by
  27. leaving that field's name blank.  There's no fancy storage algorithm,
  28. things are just stored sequentially.  But for the biggest database I've
  29. got, about 500 5-line entries, performance is just fine.
  30.  
  31. David A. Curry
  32. Research Institute for Advanced Computer Science
  33. Mail Stop 230-5
  34. NASA Ames Research Center
  35. Moffett Field, CA 94035
  36.  
  37. #! /bin/sh
  38. # This is a shell archive.  Remove anything before this line, then unpack
  39. # it by saving it into a file and typing "sh file".  To overwrite existing
  40. # files, type "sh file -c".  You can also feed this as standard input via
  41. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  42. # will see the following message at the end:
  43. #        "End of archive 1 (of 2)."
  44. # Contents:  MANIFEST Makefile README createdb.c dbfunc.c dbio.c defs.h
  45. #   index.1 main.c printdb.c samples samples/books.fmt
  46. #   samples/books.idx samples/bphone.idx samples/cdlist.fmt
  47. #   samples/cdlist.idx samples/cdwantlist.fmt samples/cdwantlist.idx
  48. #   samples/pphone.fmt samples/pphone.idx searchdb.c selectdb.c util.c
  49. # Wrapped by rsalz@papaya.bbn.com on Tue Oct 24 12:09:01 1989
  50. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  51. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  52.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  53. else
  54. echo shar: Extracting \"'MANIFEST'\" \(840 characters\)
  55. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  56. X   File Name        Archive #    Description
  57. X-----------------------------------------------------------
  58. X MANIFEST                   1    
  59. X Makefile                   1    
  60. X README                     1    
  61. X createdb.c                 1    
  62. X dbfunc.c                   1    
  63. X dbio.c                     1    
  64. X defs.h                     1    
  65. X index.1                    1    
  66. X main.c                     1    
  67. X printdb.c                  1    
  68. X samples                    1    
  69. X samples/books.fmt          1    
  70. X samples/books.idx          1    
  71. X samples/bphone.idx         1    
  72. X samples/cdlist.fmt         1    
  73. X samples/cdlist.idx         1    
  74. X samples/cdwantlist.fmt     1    
  75. X samples/cdwantlist.idx     1    
  76. X samples/pphone.fmt         1    
  77. X samples/pphone.idx         1    
  78. X screen.c                   2    
  79. X searchdb.c                 1    
  80. X selectdb.c                 1    
  81. X util.c                     1    
  82. END_OF_FILE
  83. if test 840 -ne `wc -c <'MANIFEST'`; then
  84.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  85. fi
  86. # end of 'MANIFEST'
  87. fi
  88. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  89.   echo shar: Will not clobber existing file \"'Makefile'\"
  90. else
  91. echo shar: Extracting \"'Makefile'\" \(928 characters\)
  92. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  93. X#
  94. X# $Header: /u5/davy/progs/index/RCS/Makefile,v 1.1 89/08/09 11:06:00 davy Exp $
  95. X#
  96. X# Makefile for the "index" program.
  97. X#
  98. X# David A. Curry
  99. X# Research Institute for Advanced Computer Science
  100. X# Mail Stop 230-5
  101. X# NASA Ames Research Center
  102. X# Moffett Field, CA 94035
  103. X# davy@riacs.edu
  104. X#
  105. X# $Log:    Makefile,v $
  106. X# Revision 1.1  89/08/09  11:06:00  davy
  107. X# Initial revision
  108. X# 
  109. X#
  110. XCFLAGS=    -O
  111. XLIBS=    -lcurses -ltermcap
  112. X
  113. XSRCS=    createdb.c dbfunc.c dbio.c main.c printdb.c screen.c \
  114. X    searchdb.c selectdb.c util.c
  115. XOBJS=    createdb.o dbfunc.o dbio.o main.o printdb.o screen.o \
  116. X    searchdb.o selectdb.o util.o
  117. X
  118. Xindex: $(OBJS)
  119. X    $(CC) $(CFLAGS) -o index $(OBJS) $(LIBS)
  120. X
  121. Xclean:
  122. X    rm -f a.out core index $(OBJS) \#*
  123. X
  124. Xcreatedb.o:    createdb.c defs.h
  125. Xdbfunc.o:    dbfunc.c defs.h
  126. Xdbio.o:        dbio.c defs.h
  127. Xmain.o:        main.c defs.h
  128. Xprintdb.o:    printdb.c defs.h
  129. Xscreen.o:    screen.c defs.h
  130. Xsearchdb.o:    searchdb.c defs.h
  131. Xselectdb.o:    selectdb.c defs.h
  132. Xutil.o:        util.c defs.h
  133. END_OF_FILE
  134. if test 928 -ne `wc -c <'Makefile'`; then
  135.     echo shar: \"'Makefile'\" unpacked with wrong size!
  136. fi
  137. # end of 'Makefile'
  138. fi
  139. if test -f 'README' -a "${1}" != "-c" ; then 
  140.   echo shar: Will not clobber existing file \"'README'\"
  141. else
  142. echo shar: Extracting \"'README'\" \(3220 characters\)
  143. sed "s/^X//" >'README' <<'END_OF_FILE'
  144. X                            August 9, 1989
  145. X
  146. XThis is "index", Version 1.0.
  147. X
  148. XOver the years, I've accumulated a number of files in my directory which
  149. Xhold lists of various things.  I have a list of business addresses, no
  150. Xless than three personal address and phone lists, a list of all the books
  151. XI own, a list of my compact discs, and so on.  Each of these files has a
  152. Xdifferent format, has to be maintained manually with a text editor, can
  153. Xonly be searched with "grep", and is difficult to keep nicely sorted.
  154. X
  155. XWell, I got sick and tired of this.  So, I sat down and started hacking,
  156. Xand came up with "index".  Index allows you to maintain multiple
  157. Xdatabases of textual information, each with a different format.  With
  158. Xeach database, index allows you to:
  159. X
  160. X    - add entries
  161. X    - delete entries
  162. X    - edit existing entries
  163. X    - search for entries using full regular expressions
  164. X    - control what parts of an entry are searched
  165. X    - print out entries matching a pattern
  166. X    - run all or part of the database through an arbitrary
  167. X      formatting program
  168. X
  169. XThe databases index maintains are stored as simple lines of text.  Each
  170. Xfield of an entry is a line of text, and each entry in the database is
  171. Xmade up of a fixed number of lines.  For each database, you tell index
  172. Xwhat each field's (line's) name is.  You can have multiple-line fields by
  173. Xleaving that field's name blank.  There's no fancy storage algorithm,
  174. Xthings are just stored sequentially.  But for the biggest database I've
  175. Xgot, about 500 5-line entries, performance is just fine.
  176. X
  177. XIndex uses the Berkeley curses library.  It has been tested on a Sun-3
  178. Xunder SunOS 4.0.1 (4.3BSD curses) and on a Sequent Balance under Dynix
  179. X3.0.14 (4.2BSD curses).  It should be fairly easy to port to System V -
  180. Xyou'll need to modify screen.c to resolve any curses incompatibilities,
  181. Xand you'll need to change the calls to the regular expression library
  182. Xroutines in searchdb.c to use the System V style routines.
  183. X
  184. XTo compile index, just say "make".  Then make a directory in your home
  185. Xdirectory called ".index" (or set the environment variable INDEXDIR to
  186. Xpoint somewhere else).  Now, just say "index", and you can create your
  187. Xfirst database description file.  The directory "samples" contains some
  188. Xsample database description files and formatting scripts:
  189. X
  190. X    books.idx    - for keeping a list of books sorted by author.
  191. X    books.fmt    - formats the database into a tbl input file
  192. X              which prints in two columns in landscape
  193. X              mode.
  194. X
  195. X    bphone.idx    - for a business phone/address database.
  196. X
  197. X    cdlist.idx    - for keeping a list of compact discs.
  198. X    cdlist.fmt    - formats the database into a wide landscape-mode
  199. X              tbl input file.
  200. X
  201. X    pphone.idx    - for keeping a personal phone/address database
  202. X              with home and work addresses and phone numbers
  203. X              for your friends.
  204. X    pphone.fmt    - formats the database into a troff file which
  205. X              lists each person along with their home and
  206. X              work addresses.  Useful for keeping by the
  207. X              phone or sending Xmas cards..
  208. X
  209. XSince moving all my lists into the index program, I've found things a lot
  210. Xeasier to keep track of.  I hope you'll find it as useful as I do.
  211. X
  212. XDavid A. Curry
  213. XResearch Institute for Advanced Computer Science
  214. XMail Stop 230-5
  215. XNASA Ames Research Center
  216. XMoffett Field, CA 94035
  217. X
  218. END_OF_FILE
  219. if test 3220 -ne `wc -c <'README'`; then
  220.     echo shar: \"'README'\" unpacked with wrong size!
  221. fi
  222. # end of 'README'
  223. fi
  224. if test -f 'createdb.c' -a "${1}" != "-c" ; then 
  225.   echo shar: Will not clobber existing file \"'createdb.c'\"
  226. else
  227. echo shar: Extracting \"'createdb.c'\" \(3325 characters\)
  228. sed "s/^X//" >'createdb.c' <<'END_OF_FILE'
  229. X#ifndef lint
  230. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/createdb.c,v 1.1 89/08/09 11:06:21 davy Exp $";
  231. X#endif
  232. X/*
  233. X * createdb.c - handle creating a new database.
  234. X *
  235. X * David A. Curry
  236. X * Research Institute for Advanced Computer Science
  237. X * Mail Stop 230-5
  238. X * NASA Ames Research Center
  239. X * Moffett Field, CA 94035
  240. X * davy@riacs.edu
  241. X *
  242. X * $Log:    createdb.c,v $
  243. X * Revision 1.1  89/08/09  11:06:21  davy
  244. X * Initial revision
  245. X * 
  246. X */
  247. X#include <sys/param.h>
  248. X#include <curses.h>
  249. X#include <stdio.h>
  250. X#include "defs.h"
  251. X
  252. X/*
  253. X * The message we'll print to explain what's happening.
  254. X */
  255. Xstatic struct message {
  256. X    char    *m_line;
  257. X    char    *m_arg;
  258. X} message[] = {
  259. X  { "You will now be placed into an editor so that you can create the\n",
  260. X    0 },
  261. X  { "database description file.  This file will be used by the program\n",
  262. X    0 },
  263. X  { "to prompt you for new items to be inserted into the database.\n",
  264. X    0 },
  265. X  { "\n",
  266. X    0 },
  267. X  { "Each line in this file is the name of a field.  It may be as long as\n",
  268. X    0 },
  269. X  { "you want, and may contain spaces.  The order of the lines in the file\n",
  270. X    0 },
  271. X  { "is the order you will be prompted for new information when inserting\n",
  272. X    0 },
  273. X  { "into the database.  You may leave blank lines in the file; this allows\n",
  274. X    0 },
  275. X  { "multiple-line entries for items such as addesses.  You may have a\n",
  276. X    0 },
  277. X  { "total of %d lines in the file.\n",
  278. X    (char *) MAXDBLINES },
  279. X  { "\n",
  280. X    0 },
  281. X  { "By default, all lines in an entry will be examined when searching for\n",
  282. X    0 },
  283. X  { "a pattern.  To make the program ignore a line, start that line with an\n",
  284. X    0 },
  285. X  { "exclamation point (!).\n",
  286. X    0 },
  287. X  { "\n",
  288. X    0 },
  289. X  { "The database is always sorted into ASCII collating sequence based on\n",
  290. X    0 },
  291. X  { "the contents of the first field.\n",
  292. X    0 },
  293. X  { "\n",
  294. X    0 },
  295. X  { "When you are finished, save the file and exit the editor.  You will\n",
  296. X    0 },
  297. X  { "then be placed in the main menu, where you can select other operations\n",
  298. X    0 },
  299. X  { "on the database.\n",
  300. X    0 },
  301. X  { NULL, 0 }
  302. X};
  303. X
  304. X/*
  305. X * create_db - execute an editor to allow the person to create the
  306. X *           index definition file.
  307. X */
  308. Xcreate_db(dbname)
  309. Xchar *dbname;
  310. X{
  311. X    int pid;
  312. X    char *editor;
  313. X    char *getenv();
  314. X    register int row;
  315. X    char buf[BUFSIZ], fname[MAXPATHLEN];
  316. X
  317. X    /*
  318. X     * Clear the screen and move to the top.
  319. X     */
  320. X    clear();
  321. X    move(0, 0);
  322. X
  323. X    /*
  324. X     * Print out the explanatory message.
  325. X     */
  326. X    for (row=0; message[row].m_line != NULL; row++)
  327. X        printw(message[row].m_line, message[row].m_arg);
  328. X
  329. X    /*
  330. X     * Give the user a chance to read it.  Wait till they
  331. X     * type a carriage return before proceeding.
  332. X     */
  333. X    prompt_char(++row, 0, "Type RETURN to continue: ", "\n");
  334. X
  335. X    /*
  336. X     * Use the editor the user prefers, or EDITOR if
  337. X     * he doesn't have anything set.
  338. X     */
  339. X    if ((editor = getenv("EDITOR")) == NULL)
  340. X        editor = EDITOR;
  341. X
  342. X    /*
  343. X     * Construct the file name.
  344. X     */
  345. X    sprintf(fname, "%s/%s%s", dbasedir, dbname, IDXFILE_SUFFIX);
  346. X
  347. X    /*
  348. X     * Go back to normal tty modes.
  349. X     */
  350. X    reset_modes();
  351. X
  352. X    /*
  353. X     * Spawn a child process.
  354. X     */
  355. X    if ((pid = fork()) < 0) {
  356. X        error("%s: cannot fork.\n", pname, 0, 0);
  357. X        exit(1);
  358. X    }
  359. X
  360. X    /*
  361. X     * Execute the editor.
  362. X     */
  363. X    if (pid == 0) {
  364. X        execl(editor, editor, fname, 0);
  365. X        perror(editor);
  366. X        exit(1);
  367. X    }
  368. X
  369. X    /*
  370. X     * Wait for the editor to finish.
  371. X     */
  372. X    while (wait((int *) 0) != pid)
  373. X        ;
  374. X
  375. X    /*
  376. X     * Set the tty modes up again.
  377. X     */
  378. X    set_modes();
  379. X}
  380. END_OF_FILE
  381. if test 3325 -ne `wc -c <'createdb.c'`; then
  382.     echo shar: \"'createdb.c'\" unpacked with wrong size!
  383. fi
  384. # end of 'createdb.c'
  385. fi
  386. if test -f 'dbfunc.c' -a "${1}" != "-c" ; then 
  387.   echo shar: Will not clobber existing file \"'dbfunc.c'\"
  388. else
  389. echo shar: Extracting \"'dbfunc.c'\" \(3726 characters\)
  390. sed "s/^X//" >'dbfunc.c' <<'END_OF_FILE'
  391. X#ifndef lint
  392. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/dbfunc.c,v 1.1 89/08/09 11:06:31 davy Exp $";
  393. X#endif
  394. X/*
  395. X * dbfunc.c - database functions selected from the main menu.
  396. X *
  397. X * David A. Curry
  398. X * Research Institute for Advanced Computer Science
  399. X * Mail Stop 230-5
  400. X * NASA Ames Research Center
  401. X * Moffett Field, CA 94035
  402. X * davy@riacs.edu
  403. X *
  404. X * $Log:    dbfunc.c,v $
  405. X * Revision 1.1  89/08/09  11:06:31  davy
  406. X * Initial revision
  407. X * 
  408. X */
  409. X#include <curses.h>
  410. X#include <stdio.h>
  411. X#include "defs.h"
  412. X
  413. X/*
  414. X * add_entry - add an entry to the database.
  415. X */
  416. Xadd_entry()
  417. X{
  418. X    register int i;
  419. X    struct dbfile *realloc();
  420. X
  421. X    /*
  422. X     * Search for an empty entry in the array.
  423. X     */
  424. X    for (i=0; i < dbsize; i++) {
  425. X        /*
  426. X         * Found one; use it.
  427. X         */
  428. X        if ((db[i].db_flag & DB_VALID) == 0) {
  429. X            /*
  430. X             * Clear out any old junk.
  431. X             */
  432. X            bzero(&db[i], sizeof(struct dbfile));
  433. X
  434. X            /*
  435. X             * Let the user edit the entry.
  436. X             */
  437. X            if (edit_entry(&db[i], "new")) {
  438. X                /*
  439. X                 * Mark it valid, mark the database
  440. X                 * as modified, and increase the
  441. X                 * number of entries.
  442. X                 */
  443. X                db[i].db_flag |= DB_VALID;
  444. X                dbmodified = 1;
  445. X                dbentries++;
  446. X
  447. X                /*
  448. X                 * Sort the array, to get this
  449. X                 * entry into its proper place.
  450. X                 */
  451. X                qsort(db, dbentries, sizeof(struct dbfile),
  452. X                      dbsort);
  453. X            }
  454. X
  455. X            return;
  456. X        }
  457. X    }
  458. X
  459. X    /*
  460. X     * Didn't find an empty slot, so we have to allocate
  461. X     * some more.
  462. X     */
  463. X    dbsize *= 2;
  464. X
  465. X    if ((db = realloc(db, dbsize * sizeof(struct dbfile))) == NULL) {
  466. X        error("%s: out of memory.\n", pname, 0, 0);
  467. X        exit(1);
  468. X    }
  469. X
  470. X    bzero(&db[dbentries], sizeof(struct dbfile));
  471. X
  472. X    /*
  473. X     * Let the user edit the new entry.
  474. X     */
  475. X    if (edit_entry(&db[dbentries], "new")) {
  476. X        /*
  477. X         * Mark the entry as valid, mark the
  478. X         * database as modified, and increase
  479. X         * the number of entries.
  480. X         */
  481. X        db[dbentries].db_flag |= DB_VALID;
  482. X        dbmodified = 1;
  483. X        dbentries++;
  484. X
  485. X        qsort(db, dbentries, sizeof(struct dbfile), dbsort);
  486. X    }
  487. X}
  488. X
  489. X/*
  490. X * del_entry - delete an entry from the database.
  491. X */
  492. Xdel_entry(entry)
  493. Xstruct dbfile *entry;
  494. X{
  495. X    char c;
  496. X    int x, y;
  497. X
  498. X    /*
  499. X     * Prompt the user for confirmation.
  500. X     */
  501. X    getyx(curscr, y, x);
  502. X    c = prompt_char(y, 0, "Really delete this entry? ", "YyNn");
  503. X
  504. X    /*
  505. X     * Return the status of the confirmation.
  506. X     */
  507. X    switch (c) {
  508. X    case 'Y':
  509. X    case 'y':
  510. X        return(1);
  511. X    case 'N':
  512. X    case 'n':
  513. X        return(0);
  514. X    }
  515. X}
  516. X
  517. X/*
  518. X * find_entry - search for entries using a regular expression.
  519. X */
  520. Xfind_entry()
  521. X{
  522. X    register int i;
  523. X    char pattern[BUFSIZ];
  524. X
  525. X    /*
  526. X     * Clear the screen and prompt for the pattern to
  527. X     * search for.
  528. X     */
  529. X    clear();
  530. X    prompt_str(LINES/2, 0, "Pattern to search for: ", pattern);
  531. X
  532. X    /*
  533. X     * Search.  search_db will set DB_PRINT in the entries
  534. X     * which match, and return non-zero if anything matched.
  535. X     */
  536. X    if (search_db(pattern)) {
  537. X        /*
  538. X         * Display the entries that matched.
  539. X         */
  540. X        disp_entries();
  541. X
  542. X        /*
  543. X         * Clear the DB_PRINT flags.
  544. X         */
  545. X        for (i=0; i < dbentries; i++)
  546. X            db[i].db_flag &= ~DB_PRINT;
  547. X    }
  548. X    else {
  549. X        /*
  550. X         * Nothing matched.  Tell the user.
  551. X         */
  552. X        prompt_char(LINES/2, 0,
  553. X            "No entries match pattern, type RETURN to continue: ",
  554. X            "\n");
  555. X    }
  556. X}
  557. X
  558. X/*
  559. X * read_db - run through the database entry by entry.
  560. X */
  561. Xread_db()
  562. X{
  563. X    register int i;
  564. X
  565. X    /*
  566. X     * Sort the database, so we're sure it's in order.
  567. X     */
  568. X    qsort(db, dbentries, sizeof(struct dbfile), dbsort);
  569. X
  570. X    /*
  571. X     * Set DB_PRINT in all entries.
  572. X     */
  573. X    for (i=0; i < dbentries; i++) {
  574. X        if (db[i].db_flag & DB_VALID)
  575. X            db[i].db_flag |= DB_PRINT;
  576. X    }
  577. X
  578. X    /*
  579. X     * Display the entries.
  580. X     */
  581. X    disp_entries();
  582. X
  583. X    /*
  584. X     * Clear DB_PRINT.
  585. X     */
  586. X    for (i=0; i < dbentries; i++)
  587. X        db[i].db_flag &= ~DB_PRINT;
  588. X}
  589. X
  590. X/*
  591. X * save_bye - save the database and exit.
  592. X */
  593. Xsave_bye(dbname)
  594. Xchar *dbname;
  595. X{
  596. X    /*
  597. X     * Save the database.
  598. X     */
  599. X    save_db(dbname);
  600. X
  601. X    /*
  602. X     * Exit.
  603. X     */
  604. X    byebye();
  605. X}
  606. END_OF_FILE
  607. if test 3726 -ne `wc -c <'dbfunc.c'`; then
  608.     echo shar: \"'dbfunc.c'\" unpacked with wrong size!
  609. fi
  610. # end of 'dbfunc.c'
  611. fi
  612. if test -f 'dbio.c' -a "${1}" != "-c" ; then 
  613.   echo shar: Will not clobber existing file \"'dbio.c'\"
  614. else
  615. echo shar: Extracting \"'dbio.c'\" \(5120 characters\)
  616. sed "s/^X//" >'dbio.c' <<'END_OF_FILE'
  617. X#ifndef lint
  618. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/dbio.c,v 1.1 89/08/09 11:06:36 davy Exp $";
  619. X#endif
  620. X/*
  621. X * dbio.c - database input/output routines.
  622. X *
  623. X * David A. Curry
  624. X * Research Institute for Advanced Computer Science
  625. X * Mail Stop 230-5
  626. X * NASA Ames Research Center
  627. X * Moffett Field, CA 94035
  628. X * davy@riacs.edu
  629. X *
  630. X * $Log:    dbio.c,v $
  631. X * Revision 1.1  89/08/09  11:06:36  davy
  632. X * Initial revision
  633. X * 
  634. X */
  635. X#include <sys/param.h>
  636. X#include <sys/stat.h>
  637. X#include <curses.h>
  638. X#include <stdio.h>
  639. X#include "defs.h"
  640. X
  641. Xstruct    dbfile *db;        /* array of database entries        */
  642. Xstruct    idxfile idx;        /* description of the database file    */
  643. X
  644. Xint    dbmodified = 0;        /* non-zero if database needs saving    */
  645. Xint    dbentries, dbsize;    /* number of entries, size of db array    */
  646. X
  647. X/*
  648. X * read_idxfile - read the database description file.
  649. X */
  650. Xread_idxfile(dbname)
  651. Xchar *dbname;
  652. X{
  653. X    FILE *fp;
  654. X    register int len;
  655. X    char buf[BUFSIZ], idxfile[MAXPATHLEN];
  656. X
  657. X    /*
  658. X     * Construct the file name.
  659. X     */
  660. X    sprintf(idxfile, "%s/%s%s", dbasedir, dbname, IDXFILE_SUFFIX);
  661. X
  662. X    /*
  663. X     * Open the file.
  664. X     */
  665. X    if ((fp = fopen(idxfile, "r")) == NULL) {
  666. X        error("%s: cannot open \"%s\".\n", pname, idxfile, 0);
  667. X        exit(1);
  668. X    }
  669. X
  670. X    /*
  671. X     * Zero out the structure.
  672. X     */
  673. X    bzero(&idx, sizeof(struct idxfile));
  674. X
  675. X    /*
  676. X     * Read lines from the file.
  677. X     */
  678. X    while (idx.idx_nlines < MAXDBLINES) {
  679. X        /*
  680. X         * End of file.
  681. X         */
  682. X        if (fgets(buf, sizeof(buf), fp) == NULL)
  683. X            break;
  684. X
  685. X        /*
  686. X         * Strip the newline.
  687. X         */
  688. X        len = strlen(buf) - 1;
  689. X        buf[len] = '\0';
  690. X
  691. X        /*
  692. X         * If the first character is '!', then this line
  693. X         * should not participate in searches.  Save the
  694. X         * stuff after the '!'.  Otherwise this line does
  695. X         * participate in searches, save the whole line.
  696. X         */
  697. X        if (*buf == '!') {
  698. X            idx.idx_lines[idx.idx_nlines] = savestr(buf+1);
  699. X            idx.idx_search[idx.idx_nlines] = 0;
  700. X            len--;
  701. X        }
  702. X        else {
  703. X            idx.idx_lines[idx.idx_nlines] = savestr(buf);
  704. X            idx.idx_search[idx.idx_nlines] = 1;
  705. X        }
  706. X
  707. X        /*
  708. X         * Increment the number of lines.
  709. X         */
  710. X        idx.idx_nlines++;
  711. X
  712. X        /*
  713. X         * Save the length of the longest field name.
  714. X         */
  715. X        if (len > idx.idx_maxlen)
  716. X            idx.idx_maxlen = len;
  717. X    }
  718. X
  719. X    /*
  720. X     * Close the file.
  721. X     */
  722. X    fclose(fp);
  723. X}
  724. X
  725. X/*
  726. X * read_dbfile - read the database file itself.
  727. X */
  728. Xread_dbfile(dbname)
  729. Xchar *dbname;
  730. X{
  731. X    FILE *fp;
  732. X    register int i;
  733. X    struct dbfile *malloc(), *realloc();
  734. X    char buf[BUFSIZ], dbfile[MAXPATHLEN];
  735. X
  736. X    /*
  737. X     * Allocate some entries in the array.  16 is just an
  738. X     * arbitrary number.
  739. X     */
  740. X    dbsize = 16;
  741. X    dbentries = 0;
  742. X
  743. X    if ((db = malloc(dbsize * sizeof(struct dbfile))) == NULL) {
  744. X        error("%s: out of memory.\n", pname, 0, 0);
  745. X        exit(1);
  746. X    }
  747. X
  748. X    /*
  749. X     * Construct the name of the file.
  750. X     */
  751. X    sprintf(dbfile, "%s/%s%s", dbasedir, dbname, DBFILE_SUFFIX);
  752. X
  753. X    /*
  754. X     * Open the file.
  755. X     */
  756. X    if ((fp = fopen(dbfile, "r")) == NULL)
  757. X        return;
  758. X
  759. X    /*
  760. X     * Until we hit end of file...
  761. X     */
  762. X    while (!feof(fp)) {
  763. X        /*
  764. X         * If we need to, allocate some more entries.
  765. X         */
  766. X        if (dbentries >= dbsize) {
  767. X            dbsize *= 2;
  768. X            db = realloc(db, dbsize * sizeof(struct dbfile));
  769. X
  770. X            if (db == NULL) {
  771. X                error("%s: out of memory.\n", pname, 0, 0);
  772. X                exit(1);
  773. X            }
  774. X        }
  775. X
  776. X        /*
  777. X         * Read in one entry at a time.
  778. X         */
  779. X        for (i = 0; i < idx.idx_nlines; i++) {
  780. X            /*
  781. X             * If we hit end of file before getting a
  782. X             * complete entry, toss this one.
  783. X             */
  784. X            if (fgets(buf, sizeof(buf), fp) == NULL)
  785. X                goto out;
  786. X
  787. X            /*
  788. X             * Save the length of the line, strip the
  789. X             * newline, and save the line.
  790. X             */
  791. X            db[dbentries].db_lens[i] = strlen(buf) - 1;
  792. X            buf[db[dbentries].db_lens[i]] = '\0';
  793. X
  794. X            db[dbentries].db_lines[i] = savestr(buf);
  795. X        }
  796. X
  797. X        /*
  798. X         * Mark this entry as valid and increase the
  799. X         * number of entries.
  800. X         */
  801. X        db[dbentries].db_flag = DB_VALID;
  802. X        dbentries++;
  803. X    }
  804. X
  805. Xout:
  806. X    /*
  807. X     * Make sure what we've got is sorted.
  808. X     */
  809. X    qsort(db, dbentries, sizeof(struct dbfile), dbsort);
  810. X
  811. X    fclose(fp);
  812. X}
  813. X
  814. X/*
  815. X * save_db - save the database to disk.
  816. X */
  817. Xsave_db(dbname)
  818. Xchar *dbname;
  819. X{
  820. X    FILE *fp;
  821. X    struct stat st;
  822. X    register int i, j;
  823. X    char realfile[MAXPATHLEN], bakfile[MAXPATHLEN];
  824. X
  825. X    /*
  826. X     * If it doesn't need saving, never mind.
  827. X     */
  828. X    if (!dbmodified)
  829. X        return;
  830. X
  831. X    /*
  832. X     * Create the name of the file and a backup file.
  833. X     */
  834. X    sprintf(realfile, "%s/%s%s", dbasedir, dbname, DBFILE_SUFFIX);
  835. X    sprintf(bakfile, "%s/#%s%s", dbasedir, dbname, DBFILE_SUFFIX);
  836. X
  837. X    /*
  838. X     * Default creation mode.
  839. X     */
  840. X    st.st_mode = 0400;
  841. X
  842. X    /*
  843. X     * If the file already exists, rename it to the
  844. X     * backup file name.
  845. X     */
  846. X    if (stat(realfile, &st) == 0)
  847. X        rename(realfile, bakfile);
  848. X
  849. X    /*
  850. X     * Open the new file.
  851. X     */
  852. X    if ((fp = fopen(realfile, "w")) == NULL) {
  853. X        error("%s: cannot create \"%s\".\n", pname, realfile);
  854. X        exit(1);
  855. X    }
  856. X
  857. X    /*
  858. X     * Make sure the database is sorted.
  859. X     */
  860. X    qsort(db, dbentries, sizeof(struct dbfile), dbsort);
  861. X
  862. X    /*
  863. X     * Write out the entries.
  864. X     */
  865. X    for (i=0; i < dbentries; i++) {
  866. X        if ((db[i].db_flag & DB_VALID) == 0)
  867. X            continue;
  868. X
  869. X        for (j=0; j < idx.idx_nlines; j++)
  870. X            fprintf(fp, "%s\n", db[i].db_lines[j]);
  871. X    }
  872. X
  873. X    /*
  874. X     * Set the file mode to the mode of the original
  875. X     * file.  Mark the database as unmodified.
  876. X     */
  877. X    fchmod(fileno(fp), st.st_mode & 0777);
  878. X    dbmodified = 0;
  879. X
  880. X    fclose(fp);
  881. X}
  882. END_OF_FILE
  883. if test 5120 -ne `wc -c <'dbio.c'`; then
  884.     echo shar: \"'dbio.c'\" unpacked with wrong size!
  885. fi
  886. # end of 'dbio.c'
  887. fi
  888. if test -f 'defs.h' -a "${1}" != "-c" ; then 
  889.   echo shar: Will not clobber existing file \"'defs.h'\"
  890. else
  891. echo shar: Extracting \"'defs.h'\" \(2232 characters\)
  892. sed "s/^X//" >'defs.h' <<'END_OF_FILE'
  893. X/*
  894. X * $Header: /u5/davy/progs/index/RCS/defs.h,v 1.1 89/08/09 11:06:09 davy Exp $
  895. X *
  896. X * defs.h - definitions for the index program.
  897. X *
  898. X * David A. Curry
  899. X * Research Institute for Advanced Computer Science
  900. X * Mail Stop 230-5
  901. X * NASA Ames Research Center
  902. X * Moffett Field, CA 94035
  903. X * davy@riacs.edu
  904. X *
  905. X * $Log:    defs.h,v $
  906. X * Revision 1.1  89/08/09  11:06:09  davy
  907. X * Initial revision
  908. X * 
  909. X */
  910. X#define PATCHLEVEL    0        /* level of patches applied    */
  911. X
  912. X#define MAXDBFILES    64        /* max. no. of database files    */
  913. X#define MAXDBLINES    16        /* max. no. of fields in dbase    */
  914. X
  915. X#define EDITOR        "/usr/ucb/vi"    /* editor to use when creating    */
  916. X
  917. X#define INDEXDIR    ".index"    /* directory where stuff is    */
  918. X#define DBFILE_SUFFIX    ".db"        /* database file suffix        */
  919. X#define FMTFILE_SUFFIX    ".fmt"        /* format program suffix    */
  920. X#define IDXFILE_SUFFIX    ".idx"        /* index definition suffix    */
  921. X
  922. X/*
  923. X * Values for db_flag.
  924. X */
  925. X#define DB_VALID    0x01
  926. X#define DB_PRINT    0x02
  927. X
  928. X/*
  929. X * For 4.2 curses.
  930. X */
  931. X#ifndef cbreak
  932. X#define cbreak() crmode()
  933. X#endif
  934. X#ifndef nocbreak
  935. X#define nocbreak() nocrmode()
  936. X#endif
  937. X
  938. X/*
  939. X * Usually defined in ttychars.h.
  940. X */
  941. X#ifndef CTRL
  942. X#define CTRL(c)        ('c' & 037)
  943. X#endif
  944. X
  945. X/*
  946. X * Structure to hold the contents of the index definition.
  947. X */
  948. Xstruct idxfile {
  949. X    int    idx_maxlen;        /* longest field length        */
  950. X    int    idx_nlines;        /* number of lines per entry    */
  951. X    char    idx_search[MAXDBLINES];    /* non-zero if field searchable    */
  952. X    char    *idx_lines[MAXDBLINES];    /* strings naming the fields    */
  953. X};
  954. X
  955. X/*
  956. X * Structure to hold a database entry.
  957. X */
  958. Xstruct dbfile {
  959. X    int    db_flag;        /* flag, see above        */
  960. X    int    db_lens[MAXDBLINES];    /* lengths of line contents    */
  961. X    char    *db_lines[MAXDBLINES];    /* lines in the entry        */
  962. X};
  963. X
  964. Xextern char    *pname;            /* program name            */
  965. X
  966. Xextern int    dbsize;            /* size of db array        */
  967. Xextern int    igncase;        /* non-zero if -i switch given    */
  968. Xextern int    verbose;        /* non-zero if -v switch given    */
  969. Xextern int    dbentries;        /* number of entries in db    */
  970. Xextern int    dbmodified;        /* non-zero if db needs saving    */
  971. X
  972. Xextern char    dbasedir[];        /* path to the INDEXDIR        */
  973. X
  974. Xextern struct    dbfile *db;        /* database entries array    */
  975. Xextern struct    idxfile idx;        /* index definition structure    */
  976. X
  977. Xchar        *savestr();
  978. Xchar        *select_db();
  979. X
  980. Xint        byebye();
  981. Xint        dbsort();
  982. END_OF_FILE
  983. if test 2232 -ne `wc -c <'defs.h'`; then
  984.     echo shar: \"'defs.h'\" unpacked with wrong size!
  985. fi
  986. # end of 'defs.h'
  987. fi
  988. if test -f 'index.1' -a "${1}" != "-c" ; then 
  989.   echo shar: Will not clobber existing file \"'index.1'\"
  990. else
  991. echo shar: Extracting \"'index.1'\" \(7844 characters\)
  992. sed "s/^X//" >'index.1' <<'END_OF_FILE'
  993. X.\"
  994. X.\" $Header: /u5/davy/progs/index/RCS/index.1,v 1.1 89/08/09 11:09:42 davy Exp $
  995. X.\"
  996. X.\" David A. Curry
  997. X.\" Research Institute for Advanced Computer Science
  998. X.\" Mail Stop 230-5
  999. X.\" NASA Ames Research Center
  1000. X.\" Moffett Field, CA 94035
  1001. X.\"
  1002. X.\" $Log:    index.1,v $
  1003. XRevision 1.1  89/08/09  11:09:42  davy
  1004. XInitial revision
  1005. X
  1006. X.\"
  1007. X.TH INDEX 1 "27 July 1989" LOCAL
  1008. X.SH NAME
  1009. Xindex \- maintain simple databases
  1010. X.SH SYNOPSIS
  1011. Xindex
  1012. X[
  1013. X.B \-f
  1014. X.I filter
  1015. X] [
  1016. X.B \-i
  1017. X] [
  1018. X.B \-v
  1019. X] [
  1020. X.I database
  1021. X] [
  1022. X.I pattern
  1023. X]
  1024. X.SH DESCRIPTION
  1025. X.PP
  1026. X.I Index
  1027. Xis used to maintain simple databases such as address lists,
  1028. Xlists of books or compact discs,
  1029. Xand so on.
  1030. XAll databases are stored as simple text files in a single directory.
  1031. XBy default,
  1032. Xthis directory resides in your home directory,
  1033. Xand is called
  1034. X.IR \&.index .
  1035. XYou can specify a different path name for the directory by setting
  1036. Xthe environment variable
  1037. X.B \s-1INDEXDIR\s0
  1038. Xto the directory's full path name.
  1039. X.PP
  1040. XWhen invoked with no arguments,
  1041. X.I index
  1042. Xwill present you with a list of the databases you have,
  1043. Xand ask you to select the one you want to work with.
  1044. XTo create a new database,
  1045. Xsimply type the name of a non-existent database to the prompt.
  1046. XThe name of an existing database may also be specified on the command line,
  1047. Xbypassing this step and going directly to the main menu.
  1048. X.SH CREATING A NEW DATABASE
  1049. X.PP
  1050. XWhen you specify the name of a non-existent database to the database
  1051. Xselection prompt,
  1052. Xyou will be placed in a text editor to create the database description
  1053. Xfile.
  1054. XThis file is simply a list of the field names for the database,
  1055. Xone per line.
  1056. XYou may have up to 16 fields in each database.
  1057. XBlank lines may be used for continuation lines in multiple-line fields,
  1058. Xsuch as addresses.
  1059. X.PP
  1060. XThe database is always sorted by the first field.
  1061. XWhen searching the database,
  1062. Xthe default is to search all fields for the pattern.
  1063. XTo specify that a field should be ignored in searching,
  1064. Xyou should place an exclamation point (!) in the first position on
  1065. Xthat line.
  1066. X.PP
  1067. XWhen you have created the database description file,
  1068. Xsave the file and exit the editor.
  1069. XYou will then be placed in the main menu,
  1070. Xwhere you can manipulate the database.
  1071. X.SH THE MAIN MENU
  1072. X.PP
  1073. XThe main menu is the point from which the database can be manipulated.
  1074. XThis menu provides you with several commands:
  1075. X.IP \fBa\fP
  1076. XAdd a new entry to the database.
  1077. XYou will be presented with a list of the fields in a database entry,
  1078. Xand allowed to fill them in.
  1079. XAs you type,
  1080. Xcharacters are inserted at the current cursor location.
  1081. XThe editing commands available are a subset of those provided by the
  1082. X\s-1EMACS\s0 text editor:
  1083. X.RS
  1084. X.IP \fB^A\fP
  1085. XMove the cursor to the beginning of the line.
  1086. X.IP \fB^B\fP
  1087. XMove the cursor backward one character.
  1088. X.IP \fB^D\fP
  1089. XDelete the character under the cursor.
  1090. X.IP \fB^E\fP
  1091. XMove the cursor to the end of the line.
  1092. X.IP \fB^F\fP
  1093. XMove the cursor forward one character.
  1094. X.IP \fB^H\fP
  1095. XBackspace,
  1096. Xdeleting the character in front of the cursor.
  1097. XThe \s-1DEL\s0 key also performs this function.
  1098. X.IP \fB^K\fP
  1099. XDelete from the cursor position to the end of the line.
  1100. X.IP \fB^L\fP
  1101. XRedraw the screen.
  1102. X.IP \fB<\s-1RET\s0>
  1103. XPressing \s-1RETURN\s0 moves to the next line,
  1104. Xcolumn one.
  1105. XIf you're on the last line,
  1106. Xthis wraps around to the first line.
  1107. X.IP \fB^N\fP
  1108. XMove to the next line,
  1109. Xwithout moving to column one.
  1110. XIf you're on the last line,
  1111. Xthis wraps around to the first line.
  1112. X.IP \fB^P\fP
  1113. XMove to the previous line.
  1114. XIf you're on the first line,
  1115. Xthis wraps around to the last line.
  1116. X.IP \fB<\s-1ESC\s0>\fP
  1117. XPressing the \s-1ESCAPE\s0 key tells
  1118. X.I index
  1119. Xthat you're done editing the entry.
  1120. XYou will be asked whether you want to save the entry in the database.
  1121. XIf you say yes,
  1122. Xit will be saved.
  1123. XIf you say no,
  1124. Xthe data you just entered will be discarded.
  1125. XIf you press \s-1RETURN\s0,
  1126. Xyou will be returned to the editing mode.
  1127. X.RE
  1128. X.IP \fBf\fP
  1129. XFind an entry in the database.
  1130. XYou will be prompted for a pattern to search for,
  1131. Xand then all entries which match the pattern will be displayed,
  1132. Xone at a time.
  1133. XThe pattern may be any regular expression,
  1134. Xas described in
  1135. X.IR ed (1).
  1136. XCase is distinguished unless the
  1137. X.B \-i
  1138. Xoption was given on the command line.
  1139. XSee the description of the ``\fBr\fP'' command for the options available
  1140. Xto you with each entry displayed.
  1141. X.IP \fBr\fP
  1142. XRead the database entry by entry.
  1143. XEach entry in the database is printed on the screen,
  1144. Xalong with two numbers indicating the number of entries in the database,
  1145. Xand the sequential index number of this entry (e.g., ``123/500'').
  1146. XAs each entry is printed,
  1147. Xyou will be allowed to execute the following commands:
  1148. X.RS
  1149. X.IP \fB<\s-1RET\s0>\fP
  1150. XPressing the \s-1RETURN\s0 key will move to the next database entry.
  1151. X.IP \fB\-\fP
  1152. XReturn to the previous database entry.
  1153. X.IP \fBd\fP
  1154. XDelete this entry from the database.
  1155. XYou will be prompted to confirm this operation.
  1156. X.IP \fBe\fP
  1157. XEdit this database entry.
  1158. XSee the description of the main menu ``\fBa\fP'' command for a list
  1159. Xof the editing commands available.
  1160. XAfter you press \s-1ESCAPE\s0 and indicate whether you wish to save what
  1161. Xyou have edited,
  1162. Xyou will be returned to this mode again.
  1163. X.IP \fBq\fP
  1164. XReturn to the main menu without looking at the rest of the entries.
  1165. X.IP \fB^L\fP
  1166. XRedraw the screen.
  1167. X.RE
  1168. X.IP \fBs\fP
  1169. XSave any modifications to the database.
  1170. X.IP \fBq\fP
  1171. XSave any modifications to the database,
  1172. Xand exit
  1173. X.IR index .
  1174. X.IP \fBx\fP
  1175. XExit
  1176. X.I index
  1177. Xwithout saving the database.
  1178. XIf the database has been modified,
  1179. Xyou will be asked to confirm this operation.
  1180. X.SH SEARCHING FROM THE COMMAND LINE
  1181. X.PP
  1182. XIf a database name and pattern are both specified on the command line,
  1183. Xthe pattern will be searched for in the database,
  1184. Xand any matching entries will be printed on the standard output.
  1185. XEach entry will be printed one field per line,
  1186. Xpreceded by its field name.
  1187. X.PP
  1188. XThe pattern may be any valid regular expression,
  1189. Xas defined by
  1190. X.IR ed (1).
  1191. XCase is significant,
  1192. Xunless the
  1193. X.B \-i
  1194. Xoption is given.
  1195. XTo match all entries in the database,
  1196. Xuse the regular expression ``.'' (matches any character).
  1197. X.PP
  1198. XBy default,
  1199. X.I index
  1200. Xwill not print any blank lines in the entry,
  1201. Xin order to make the output more readable.
  1202. XBy specifying the
  1203. X.B \-v
  1204. Xoption,
  1205. Xyou can tell
  1206. X.I index
  1207. Xto print all lines in the entry,
  1208. Xeven if they have nothing on them.
  1209. X.SH FILTERS
  1210. X.PP
  1211. XIf the
  1212. X.B \-f
  1213. Xoption is specified with the name of a filter,
  1214. Xthen when a database name and pattern are also given,
  1215. Xall matching entries will be sent through the filter program instead
  1216. Xof to the standard output.
  1217. X.PP
  1218. XThe first line of output will contain the field names for the database,
  1219. Xseparated by tabs.
  1220. XEach following line will contain one database entry,
  1221. Xwith fields separated by tabs.
  1222. XThis format is easily dealt with using programs such as
  1223. X.IR awk (1).
  1224. X.PP
  1225. XAs a convenience,
  1226. Xfiltering programs may be stored in the database directory with a
  1227. X``.fmt'' extension in their file name.
  1228. XThe program is first searched for here (by adding the name extension),
  1229. Xand if it is not found,
  1230. Xit is then searched for (without the extension) in the standard search
  1231. Xpath.
  1232. X.SH EXAMPLE
  1233. X.PP
  1234. XThe following database description file implements a business phone number
  1235. Xlist.
  1236. XIt allows three lines for the company address,
  1237. Xand two lines for electronic mail addresses.
  1238. XThe extra fields ``Product'' and ``Keywords'' can be used to provide
  1239. Xadditional patterns to search for (e.g.,
  1240. Xyou might want to search for all disk vendors).
  1241. XThe ``!'' character inhibits searching the title,
  1242. Xaddress,
  1243. Xand telephone number for patterns.
  1244. X.sp
  1245. X.nf
  1246. XName
  1247. X!Title
  1248. XCompany
  1249. X!Address
  1250. X!
  1251. X!
  1252. X!Phone
  1253. XElectronic Mail
  1254. X
  1255. XProduct
  1256. XKeywords
  1257. X.fi
  1258. X.SH LIMITATIONS
  1259. X.PP
  1260. XEach database may have no more than 16 fields.
  1261. X.PP
  1262. XYou may not have more than 64 separate databases.
  1263. X.PP
  1264. XA database may contain as many entries as you can allocate memory for.
  1265. X.SH SEE ALSO
  1266. X.IR awk (1),
  1267. X.IR ed (1)
  1268. X.SH AUTHOR
  1269. XDavid A. Curry, Research Institute for Advanced Computer Science
  1270. END_OF_FILE
  1271. if test 7844 -ne `wc -c <'index.1'`; then
  1272.     echo shar: \"'index.1'\" unpacked with wrong size!
  1273. fi
  1274. # end of 'index.1'
  1275. fi
  1276. if test -f 'main.c' -a "${1}" != "-c" ; then 
  1277.   echo shar: Will not clobber existing file \"'main.c'\"
  1278. else
  1279. echo shar: Extracting \"'main.c'\" \(1996 characters\)
  1280. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  1281. X#ifndef lint
  1282. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/main.c,v 1.1 89/08/09 11:06:42 davy Exp $";
  1283. X#endif
  1284. X/*
  1285. X * main.c - main routine for index program.
  1286. X *
  1287. X * David A. Curry
  1288. X * Research Institute for Advanced Computer Science
  1289. X * Mail Stop 230-5
  1290. X * NASA Ames Research Center
  1291. X * Moffett Field, CA 94035
  1292. X * davy@riacs.edu
  1293. X *
  1294. X * $Log:    main.c,v $
  1295. X * Revision 1.1  89/08/09  11:06:42  davy
  1296. X * Initial revision
  1297. X * 
  1298. X */
  1299. X#include <sys/param.h>
  1300. X#include <curses.h>
  1301. X#include <stdio.h>
  1302. X#include "defs.h"
  1303. X
  1304. Xint    igncase = 0;            /* non-zero if -i flag given    */
  1305. Xint    verbose = 0;            /* non-zero if -v flag given    */
  1306. X
  1307. Xchar    *pname;                /* program name            */
  1308. Xchar    dbasedir[MAXPATHLEN];        /* path to database directory    */
  1309. X
  1310. Xmain(argc, argv)
  1311. Xchar **argv;
  1312. Xint argc;
  1313. X{
  1314. X    char *database, *filter, *pattern;
  1315. X
  1316. X    pname = *argv;
  1317. X    database = filter = pattern = NULL;
  1318. X
  1319. X    /*
  1320. X     * Process arguments.
  1321. X     */
  1322. X    while (--argc) {
  1323. X        if (**++argv == '-') {
  1324. X            switch (*++*argv) {
  1325. X            case 'f':            /* filter    */
  1326. X                if (--argc <= 0)
  1327. X                    usage();
  1328. X
  1329. X                filter = *++argv;
  1330. X                continue;
  1331. X            case 'i':            /* ignore case    */
  1332. X                igncase++;
  1333. X                continue;
  1334. X            case 'v':            /* verbose    */
  1335. X                verbose++;
  1336. X                continue;
  1337. X            }
  1338. X        }
  1339. X
  1340. X        /*
  1341. X         * database argument is first.
  1342. X         */
  1343. X        if (database == NULL) {
  1344. X            database = *argv;
  1345. X            continue;
  1346. X        }
  1347. X
  1348. X        /*
  1349. X         * pattern argument is next.
  1350. X         */
  1351. X        if (pattern == NULL) {
  1352. X            pattern = *argv;
  1353. X            continue;
  1354. X        }
  1355. X
  1356. X        usage();
  1357. X    }
  1358. X
  1359. X    /*
  1360. X     * Get the path of the database directory.
  1361. X     */
  1362. X    set_dbase_dir();
  1363. X
  1364. X    /*
  1365. X     * If they didn't specify a database, put them in
  1366. X     * the selection routine.
  1367. X     */
  1368. X    if (database == NULL)
  1369. X        database = select_db();
  1370. X
  1371. X    /*
  1372. X     * Open the database and read it in.
  1373. X     */
  1374. X    read_idxfile(database);
  1375. X    read_dbfile(database);
  1376. X
  1377. X    /*
  1378. X     * If they didn't specify a pattern, go to the
  1379. X     * main menu.  Otherwise, search the database
  1380. X     * for the pattern, and print the results.
  1381. X     */
  1382. X    if (pattern == NULL) {
  1383. X        main_menu(database);
  1384. X        reset_modes();
  1385. X    }
  1386. X    else {
  1387. X        search_db(pattern);
  1388. X        print_db(database, filter);
  1389. X    }
  1390. X
  1391. X    exit(0);
  1392. X}
  1393. END_OF_FILE
  1394. if test 1996 -ne `wc -c <'main.c'`; then
  1395.     echo shar: \"'main.c'\" unpacked with wrong size!
  1396. fi
  1397. # end of 'main.c'
  1398. fi
  1399. if test -f 'printdb.c' -a "${1}" != "-c" ; then 
  1400.   echo shar: Will not clobber existing file \"'printdb.c'\"
  1401. else
  1402. echo shar: Extracting \"'printdb.c'\" \(2557 characters\)
  1403. sed "s/^X//" >'printdb.c' <<'END_OF_FILE'
  1404. X#ifndef lint
  1405. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/printdb.c,v 1.1 89/08/09 11:06:47 davy Exp $";
  1406. X#endif
  1407. X/*
  1408. X * printdb.c - print entries from the database.
  1409. X *
  1410. X * David A. Curry
  1411. X * Research Institute for Advanced Computer Science
  1412. X * Mail Stop 230-5
  1413. X * NASA Ames Research Center
  1414. X * Moffett Field, CA 94035
  1415. X * davy@riacs.edu
  1416. X *
  1417. X * $Log:    printdb.c,v $
  1418. X * Revision 1.1  89/08/09  11:06:47  davy
  1419. X * Initial revision
  1420. X * 
  1421. X */
  1422. X#include <sys/file.h>
  1423. X#include <stdio.h>
  1424. X#include "defs.h"
  1425. X
  1426. X/*
  1427. X * print_db - print out entries marked DB_PRINT in the database.
  1428. X */
  1429. Xprint_db(dbname, filter)
  1430. Xchar *dbname, *filter;
  1431. X{
  1432. X    FILE *pp;
  1433. X    FILE *popen();
  1434. X    char buf[BUFSIZ];
  1435. X    register int i, j;
  1436. X    register char *tab;
  1437. X
  1438. X    /*
  1439. X     * If no filter was specified, we just spit the entries out,
  1440. X     * with their field names, to standard output.
  1441. X     */
  1442. X    if (filter == NULL) {
  1443. X        for (i=0; i < dbentries; i++) {
  1444. X            if ((db[i].db_flag & DB_VALID) == 0)
  1445. X                continue;
  1446. X            if ((db[i].db_flag & DB_PRINT) == 0)
  1447. X                continue;
  1448. X
  1449. X            for (j=0; j < idx.idx_nlines; j++) {
  1450. X                if (!verbose) {
  1451. X                    if (db[i].db_lines[j][0] == '\0')
  1452. X                        continue;
  1453. X                }
  1454. X
  1455. X                sprintf(buf, "%s%s", idx.idx_lines[j],
  1456. X                    idx.idx_lines[j][0] ? ":" : "");
  1457. X                printf("%-*s%s\n", idx.idx_maxlen + 2,
  1458. X                       buf, db[i].db_lines[j]);
  1459. X            }
  1460. X
  1461. X            putchar('\n');
  1462. X        }
  1463. X
  1464. X        return;
  1465. X    }
  1466. X
  1467. X    /*
  1468. X     * Otherwise, we set up a pipe to the filter, and print
  1469. X     * first the field names, and then the fields.  We do
  1470. X     * this one entry per line, with fields separated by
  1471. X     * tabs.
  1472. X     */
  1473. X
  1474. X    /*
  1475. X     * Create the path to a formatting program in the database
  1476. X     * directory.
  1477. X     */
  1478. X    sprintf(buf, "%s/%s%s", dbasedir, filter, FMTFILE_SUFFIX);
  1479. X
  1480. X    /*
  1481. X     * If that's not there, then assume they gave us some
  1482. X     * program name (like "more" or something), and just
  1483. X     * stick it in there.
  1484. X     */
  1485. X    if (access(buf, X_OK) < 0)
  1486. X        strcpy(buf, filter);
  1487. X
  1488. X    /*
  1489. X     * Open the pipe.
  1490. X     */
  1491. X    if ((pp = popen(buf, "w")) == NULL) {
  1492. X        error("%s: cannot execute \"%s\".\n", pname, filter, 0);
  1493. X        exit(1);
  1494. X    }
  1495. X
  1496. X    /*
  1497. X     * Print the field names, separated by tabs.
  1498. X     */
  1499. X    tab = "";
  1500. X    for (i=0; i < idx.idx_nlines; i++) {
  1501. X        fprintf(pp, "%s%s", tab, idx.idx_lines[i]);
  1502. X        tab = "\t";
  1503. X    }
  1504. X
  1505. X    putc('\n', pp);
  1506. X
  1507. X    /*
  1508. X     * Print the entries, with fields separated
  1509. X     * by tabs.
  1510. X     */
  1511. X    for (i=0; i < dbentries; i++) {
  1512. X        if ((db[i].db_flag & DB_VALID) == 0)
  1513. X            continue;
  1514. X        if ((db[i].db_flag & DB_PRINT) == 0)
  1515. X            continue;
  1516. X
  1517. X        tab = "";
  1518. X        for (j=0; j < idx.idx_nlines; j++) {
  1519. X            fprintf(pp, "%s%s", tab, db[i].db_lines[j]);
  1520. X            tab = "\t";
  1521. X        }
  1522. X
  1523. X        putc('\n', pp);
  1524. X    }
  1525. X
  1526. X    /*
  1527. X     * Close the pipe.
  1528. X     */
  1529. X    pclose(pp);
  1530. X}
  1531. END_OF_FILE
  1532. if test 2557 -ne `wc -c <'printdb.c'`; then
  1533.     echo shar: \"'printdb.c'\" unpacked with wrong size!
  1534. fi
  1535. # end of 'printdb.c'
  1536. fi
  1537. if test ! -d 'samples' ; then
  1538.     echo shar: Creating directory \"'samples'\"
  1539.     mkdir 'samples'
  1540. fi
  1541. if test -f 'samples/books.fmt' -a "${1}" != "-c" ; then 
  1542.   echo shar: Will not clobber existing file \"'samples/books.fmt'\"
  1543. else
  1544. echo shar: Extracting \"'samples/books.fmt'\" \(616 characters\)
  1545. sed "s/^X//" >'samples/books.fmt' <<'END_OF_FILE'
  1546. X#!/bin/sh
  1547. X#
  1548. X# books.fmt - format the books database into a nice troff-able list
  1549. X#
  1550. X
  1551. X#
  1552. X# Put out troff header (set point size, etc.)
  1553. X#
  1554. Xcat << EOF
  1555. X.\"
  1556. X.\" Run me off with "tbl | troff -ms"
  1557. X.\" Then use "psdit -p/land.pro"
  1558. X.\"
  1559. X.nr LL 10.25i
  1560. X.nr PO .25i
  1561. X.nr HM .5i
  1562. X.nr FM .5i
  1563. X.nr PS 6
  1564. X.nr VS 8
  1565. X.ll 10.25i
  1566. X.po .25i
  1567. X.pl 8.5i
  1568. X.ps 6
  1569. X.vs 8
  1570. X.OH "''%'\*(DY'"
  1571. X.EH "''%'\*(DY'"
  1572. X.ND
  1573. X.P1
  1574. X.2C
  1575. X.TS H
  1576. Xc c c c c
  1577. Xl l l l c.
  1578. XEOF
  1579. X
  1580. X#
  1581. X# Let awk handle reformatting.
  1582. X#
  1583. Xawk    'BEGIN    { FS = "\t" }
  1584. X        { printf "%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5
  1585. X          if (NR == 1)
  1586. X            printf "=\n.TH\n"
  1587. X        }'
  1588. X
  1589. X#
  1590. X# Put out troff footer.
  1591. X#
  1592. Xcat << EOF
  1593. X.TE
  1594. XEOF
  1595. END_OF_FILE
  1596. if test 616 -ne `wc -c <'samples/books.fmt'`; then
  1597.     echo shar: \"'samples/books.fmt'\" unpacked with wrong size!
  1598. fi
  1599. chmod +x 'samples/books.fmt'
  1600. # end of 'samples/books.fmt'
  1601. fi
  1602. if test -f 'samples/books.idx' -a "${1}" != "-c" ; then 
  1603.   echo shar: Will not clobber existing file \"'samples/books.idx'\"
  1604. else
  1605. echo shar: Extracting \"'samples/books.idx'\" \(46 characters\)
  1606. sed "s/^X//" >'samples/books.idx' <<'END_OF_FILE'
  1607. XAuthor
  1608. XTitle
  1609. X!Addt'l Author(s)
  1610. XSeries
  1611. X!Status
  1612. END_OF_FILE
  1613. if test 46 -ne `wc -c <'samples/books.idx'`; then
  1614.     echo shar: \"'samples/books.idx'\" unpacked with wrong size!
  1615. fi
  1616. # end of 'samples/books.idx'
  1617. fi
  1618. if test -f 'samples/bphone.idx' -a "${1}" != "-c" ; then 
  1619.   echo shar: Will not clobber existing file \"'samples/bphone.idx'\"
  1620. else
  1621. echo shar: Extracting \"'samples/bphone.idx'\" \(74 characters\)
  1622. sed "s/^X//" >'samples/bphone.idx' <<'END_OF_FILE'
  1623. XName
  1624. X!Title
  1625. XCompany
  1626. X!Address
  1627. X!
  1628. X!
  1629. X!Phone
  1630. XElectronic Mail
  1631. X
  1632. XProduct
  1633. XKeywords
  1634. END_OF_FILE
  1635. if test 74 -ne `wc -c <'samples/bphone.idx'`; then
  1636.     echo shar: \"'samples/bphone.idx'\" unpacked with wrong size!
  1637. fi
  1638. # end of 'samples/bphone.idx'
  1639. fi
  1640. if test -f 'samples/cdlist.fmt' -a "${1}" != "-c" ; then 
  1641.   echo shar: Will not clobber existing file \"'samples/cdlist.fmt'\"
  1642. else
  1643. echo shar: Extracting \"'samples/cdlist.fmt'\" \(635 characters\)
  1644. sed "s/^X//" >'samples/cdlist.fmt' <<'END_OF_FILE'
  1645. X#!/bin/sh
  1646. X#
  1647. X# cdlist.fmt - format the cdlist database into a nice troff-able list
  1648. X#
  1649. X#
  1650. X
  1651. X#
  1652. X# Put out troff header (set point size, etc.)
  1653. X#
  1654. Xcat << EOF
  1655. X.\"
  1656. X.\" Run me off with "tbl | troff -ms"
  1657. X.\" Then use "psdit -p/land.pro"
  1658. X.\"
  1659. X.nr LL 10i
  1660. X.nr PO .5i
  1661. X.nr HM .5i
  1662. X.nr FM .5i
  1663. X.nr PS 9
  1664. X.nr VS 11
  1665. X.ll 10i
  1666. X.po 0.5i
  1667. X.pl 8.5i
  1668. X.ps 9
  1669. X.vs 11
  1670. X.TS H
  1671. Xcenter, expand;
  1672. Xc s s s s s
  1673. Xc c c c c c
  1674. Xl l l l l l.
  1675. XCompact Disc List - \*(DY
  1676. XEOF
  1677. X
  1678. X#
  1679. X# Let awk handle reformatting.
  1680. X#
  1681. Xawk    'BEGIN    { FS = "\t" }
  1682. X        { printf "%s\t%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5, $6
  1683. X          if (NR == 1)
  1684. X            printf "=\n.TH\n"
  1685. X        }'
  1686. X
  1687. X#
  1688. X# Put out troff footer.
  1689. X#
  1690. Xcat << EOF
  1691. X.TE
  1692. XEOF
  1693. END_OF_FILE
  1694. if test 635 -ne `wc -c <'samples/cdlist.fmt'`; then
  1695.     echo shar: \"'samples/cdlist.fmt'\" unpacked with wrong size!
  1696. fi
  1697. chmod +x 'samples/cdlist.fmt'
  1698. # end of 'samples/cdlist.fmt'
  1699. fi
  1700. if test -f 'samples/cdlist.idx' -a "${1}" != "-c" ; then 
  1701.   echo shar: Will not clobber existing file \"'samples/cdlist.idx'\"
  1702. else
  1703. echo shar: Extracting \"'samples/cdlist.idx'\" \(54 characters\)
  1704. sed "s/^X//" >'samples/cdlist.idx' <<'END_OF_FILE'
  1705. XArtist
  1706. XTitle
  1707. X!Orchestra
  1708. XClassification
  1709. X!Label
  1710. X!Number
  1711. END_OF_FILE
  1712. if test 54 -ne `wc -c <'samples/cdlist.idx'`; then
  1713.     echo shar: \"'samples/cdlist.idx'\" unpacked with wrong size!
  1714. fi
  1715. # end of 'samples/cdlist.idx'
  1716. fi
  1717. if test -f 'samples/cdwantlist.fmt' -a "${1}" != "-c" ; then 
  1718.   echo shar: Will not clobber existing file \"'samples/cdwantlist.fmt'\"
  1719. else
  1720. echo shar: Extracting \"'samples/cdwantlist.fmt'\" \(650 characters\)
  1721. sed "s/^X//" >'samples/cdwantlist.fmt' <<'END_OF_FILE'
  1722. X#!/bin/sh
  1723. X#
  1724. X# cdwantlist.fmt - format the cdwantlist database into a nice troff-able list
  1725. X#
  1726. X#
  1727. X
  1728. X#
  1729. X# Put out troff header (set point size, etc.)
  1730. X#
  1731. Xcat << EOF
  1732. X.\"
  1733. X.\" Run me off with "tbl | troff -ms"
  1734. X.\" Then use "psdit -p/land.pro"
  1735. X.\"
  1736. X.nr LL 10i
  1737. X.nr PO .5i
  1738. X.nr HM .5i
  1739. X.nr FM .5i
  1740. X.nr PS 9
  1741. X.nr VS 11
  1742. X.ll 10.0i
  1743. X.po 0.5i
  1744. X.pl 8.5i
  1745. X.ps 9
  1746. X.vs 11
  1747. X.TS H
  1748. Xcenter, expand;
  1749. Xc s s s s s
  1750. Xc c c c c c
  1751. Xl l l l l l.
  1752. XCompact Disc Want List - \*(DY
  1753. XEOF
  1754. X
  1755. X#
  1756. X# Let awk handle reformatting.
  1757. X#
  1758. Xawk    'BEGIN    { FS = "\t" }
  1759. X        { printf "%s\t%s\t%s\t%s\t%s\t%s\n", $1, $2, $3, $4, $5, $6
  1760. X          if (NR == 1)
  1761. X            printf "=\n.TH\n"
  1762. X        }'
  1763. X
  1764. X#
  1765. X# Put out troff footer.
  1766. X#
  1767. Xcat << EOF
  1768. X.TE
  1769. XEOF
  1770. END_OF_FILE
  1771. if test 650 -ne `wc -c <'samples/cdwantlist.fmt'`; then
  1772.     echo shar: \"'samples/cdwantlist.fmt'\" unpacked with wrong size!
  1773. fi
  1774. chmod +x 'samples/cdwantlist.fmt'
  1775. # end of 'samples/cdwantlist.fmt'
  1776. fi
  1777. if test -f 'samples/cdwantlist.idx' -a "${1}" != "-c" ; then 
  1778.   echo shar: Will not clobber existing file \"'samples/cdwantlist.idx'\"
  1779. else
  1780. echo shar: Extracting \"'samples/cdwantlist.idx'\" \(54 characters\)
  1781. sed "s/^X//" >'samples/cdwantlist.idx' <<'END_OF_FILE'
  1782. XArtist
  1783. XTitle
  1784. X!Orchestra
  1785. XClassification
  1786. X!Label
  1787. X!Number
  1788. END_OF_FILE
  1789. if test 54 -ne `wc -c <'samples/cdwantlist.idx'`; then
  1790.     echo shar: \"'samples/cdwantlist.idx'\" unpacked with wrong size!
  1791. fi
  1792. # end of 'samples/cdwantlist.idx'
  1793. fi
  1794. if test -f 'samples/pphone.fmt' -a "${1}" != "-c" ; then 
  1795.   echo shar: Will not clobber existing file \"'samples/pphone.fmt'\"
  1796. else
  1797. echo shar: Extracting \"'samples/pphone.fmt'\" \(1453 characters\)
  1798. sed "s/^X//" >'samples/pphone.fmt' <<'END_OF_FILE'
  1799. X#!/bin/sh
  1800. X#
  1801. X# pphone.fmt - format the pphone database into a nice troff-able
  1802. X#           phone list of the format
  1803. X#
  1804. X#    Name in bold face
  1805. X#       Home Address        Work Address
  1806. X#       Home Phone        Work Phone
  1807. X#                Electronic Mail Address
  1808. X#
  1809. X
  1810. X#
  1811. X# Put out troff header (set point size, etc.)
  1812. X#
  1813. Xcat << EOF
  1814. X.\"
  1815. X.\" Run me off with "troff -ms"
  1816. X.\"
  1817. X.nr LL 6.5i
  1818. X.nr PO 1i
  1819. X.nr PS 12
  1820. X.nr VS 14
  1821. X.ll 6.5i
  1822. X.po 1i
  1823. X.ps 12
  1824. X.vs 14
  1825. X.nf
  1826. XEOF
  1827. X
  1828. X#
  1829. X# Let awk handle reformatting.  Basically, we want to print out, for
  1830. X# each entry:
  1831. X#
  1832. X#    .ne 6v        <-- makes sure whole entry fits on page
  1833. X#    .B "Name"
  1834. X#    .mk
  1835. X#    .in .5i
  1836. X#    Home Address
  1837. X#    Home Phone
  1838. X#    .rt
  1839. X#    .in 3i
  1840. X#    Work Address
  1841. X#    Work Phone
  1842. X#    Electronic Address
  1843. X#    .sp
  1844. X#
  1845. X# We have special stuff to handle blank lines in the home and/or work
  1846. X# address, and then at the end we have to put in some blank lines to
  1847. X# make sure the work address is at least as long as the home address,
  1848. X# since we're using marks/returns.
  1849. X#
  1850. Xawk    'BEGIN    { FS = "\t" }
  1851. X        { if (NR > 1) {
  1852. X            home = ""
  1853. X            homen = 0
  1854. X            for (i=2; i <= 4; i++) {
  1855. X                if (length($i) > 0) {
  1856. X                    home = home $i "\n"
  1857. X                    homen++
  1858. X                }
  1859. X            }
  1860. X
  1861. X            work = ""
  1862. X            workn = 0
  1863. X            for (i=5; i <= 9; i++) {
  1864. X                if (length($i) > 0) {
  1865. X                    work = work $i "\n"
  1866. X                    workn++
  1867. X                }
  1868. X            }
  1869. X
  1870. X            printf ".ne 6v\n.B \"%s\"\n", $1
  1871. X            printf ".in .5i\n.mk\n"
  1872. X            printf "%s", home
  1873. X            printf ".rt\n.in 3i\n"
  1874. X            printf "%s", work
  1875. X
  1876. X            while (homen > workn) {
  1877. X                printf "\n"
  1878. X                homen--
  1879. X            }
  1880. X
  1881. X            printf ".sp\n.in 0\n"
  1882. X          }
  1883. X        }'
  1884. END_OF_FILE
  1885. if test 1453 -ne `wc -c <'samples/pphone.fmt'`; then
  1886.     echo shar: \"'samples/pphone.fmt'\" unpacked with wrong size!
  1887. fi
  1888. chmod +x 'samples/pphone.fmt'
  1889. # end of 'samples/pphone.fmt'
  1890. fi
  1891. if test -f 'samples/pphone.idx' -a "${1}" != "-c" ; then 
  1892.   echo shar: Will not clobber existing file \"'samples/pphone.idx'\"
  1893. else
  1894. echo shar: Extracting \"'samples/pphone.idx'\" \(89 characters\)
  1895. sed "s/^X//" >'samples/pphone.idx' <<'END_OF_FILE'
  1896. XName
  1897. X!Home Address
  1898. X!
  1899. X!Home Phone
  1900. X!Work Address
  1901. X!
  1902. X!
  1903. X!Work Phone
  1904. XElectronic Mail
  1905. X!Birthday
  1906. END_OF_FILE
  1907. if test 89 -ne `wc -c <'samples/pphone.idx'`; then
  1908.     echo shar: \"'samples/pphone.idx'\" unpacked with wrong size!
  1909. fi
  1910. # end of 'samples/pphone.idx'
  1911. fi
  1912. if test -f 'searchdb.c' -a "${1}" != "-c" ; then 
  1913.   echo shar: Will not clobber existing file \"'searchdb.c'\"
  1914. else
  1915. echo shar: Extracting \"'searchdb.c'\" \(1943 characters\)
  1916. sed "s/^X//" >'searchdb.c' <<'END_OF_FILE'
  1917. X#ifndef lint
  1918. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/searchdb.c,v 1.1 89/08/09 11:06:59 davy Exp $";
  1919. X#endif
  1920. X/*
  1921. X * searchdb.c - database search routine.
  1922. X *
  1923. X * David A. Curry
  1924. X * Research Institute for Advanced Computer Science
  1925. X * Mail Stop 230-5
  1926. X * NASA Ames Research Center
  1927. X * Moffett Field, CA 94035
  1928. X * davy@riacs.edu
  1929. X *
  1930. X * $Log:    searchdb.c,v $
  1931. X * Revision 1.1  89/08/09  11:06:59  davy
  1932. X * Initial revision
  1933. X * 
  1934. X */
  1935. X#include <curses.h>
  1936. X#include <ctype.h>
  1937. X#include <stdio.h>
  1938. X#include "defs.h"
  1939. X
  1940. X/*
  1941. X * search_db - search the database for the pattern.
  1942. X */
  1943. Xsearch_db(pattern)
  1944. Xchar *pattern;
  1945. X{
  1946. X    int code = 0;
  1947. X    char *re_comp();
  1948. X    char buf[BUFSIZ];
  1949. X    register int i, j;
  1950. X    register char *p, *q;
  1951. X
  1952. X    /*
  1953. X     * If we're ignoring case, convert the pattern
  1954. X     * to all lower case.
  1955. X     */
  1956. X    if (igncase) {
  1957. X        for (p = pattern; *p != NULL; p++) {
  1958. X            if (isupper(*p))
  1959. X                *p = tolower(*p);
  1960. X        }
  1961. X    }
  1962. X
  1963. X    /*
  1964. X     * Compile the regular expression.
  1965. X     */
  1966. X    if (re_comp(pattern) != NULL)
  1967. X        return(0);
  1968. X
  1969. X    /*
  1970. X     * For all entries...
  1971. X     */
  1972. X    for (i=0; i < dbentries; i++) {
  1973. X        /*
  1974. X         * For each line in the entry...
  1975. X         */
  1976. X        for (j=0; j < idx.idx_nlines; j++) {
  1977. X            /*
  1978. X             * If this line is not to be searched,
  1979. X             * skip it.
  1980. X             */
  1981. X            if (idx.idx_search[j] == 0)
  1982. X                continue;
  1983. X
  1984. X            /*
  1985. X             * If ignoring case, copy the line an
  1986. X             * convert it to lower case.  Otherwise,
  1987. X             * use it as is.
  1988. X             */
  1989. X            if (igncase) {
  1990. X                p = db[i].db_lines[j];
  1991. X                q = buf;
  1992. X
  1993. X                while (*p != NULL) {
  1994. X                    *q++ = isupper(*p) ? tolower(*p) : *p;
  1995. X                    p++;
  1996. X                }
  1997. X
  1998. X                *q = '\0';
  1999. X
  2000. X                /*
  2001. X                 * If we get a match, mark this entry as
  2002. X                 * printable.
  2003. X                 */
  2004. X                if (re_exec(buf)) {
  2005. X                    db[i].db_flag |= DB_PRINT;
  2006. X                    code = 1;
  2007. X                }
  2008. X            }
  2009. X            else {
  2010. X                /*
  2011. X                 * If we get a match, mark this entry
  2012. X                 * as printable.
  2013. X                 */
  2014. X                if (re_exec(db[i].db_lines[j])) {
  2015. X                    db[i].db_flag |= DB_PRINT;
  2016. X                    code = 1;
  2017. X                }
  2018. X            }
  2019. X        }
  2020. X    }
  2021. X
  2022. X    /*
  2023. X     * Return whether or not we found anything.
  2024. X     */
  2025. X    return(code);
  2026. X}
  2027. X
  2028. END_OF_FILE
  2029. if test 1943 -ne `wc -c <'searchdb.c'`; then
  2030.     echo shar: \"'searchdb.c'\" unpacked with wrong size!
  2031. fi
  2032. # end of 'searchdb.c'
  2033. fi
  2034. if test -f 'selectdb.c' -a "${1}" != "-c" ; then 
  2035.   echo shar: Will not clobber existing file \"'selectdb.c'\"
  2036. else
  2037. echo shar: Extracting \"'selectdb.c'\" \(2630 characters\)
  2038. sed "s/^X//" >'selectdb.c' <<'END_OF_FILE'
  2039. X#ifndef lint
  2040. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/selectdb.c,v 1.1 89/08/09 11:07:06 davy Exp $";
  2041. X#endif
  2042. X/*
  2043. X * selectdb.c - database selection routines.
  2044. X *
  2045. X * David A. Curry
  2046. X * Research Institute for Advanced Computer Science
  2047. X * Mail Stop 230-5
  2048. X * NASA Ames Research Center
  2049. X * Moffett Field, CA 94035
  2050. X * davy@riacs.edu
  2051. X *
  2052. X * $Log:    selectdb.c,v $
  2053. X * Revision 1.1  89/08/09  11:07:06  davy
  2054. X * Initial revision
  2055. X * 
  2056. X */
  2057. X#include <sys/param.h>
  2058. X#include <sys/dir.h>
  2059. X#include <curses.h>
  2060. X#include <stdio.h>
  2061. X#include "defs.h"
  2062. X
  2063. X/*
  2064. X * select_db - allow the user to select a database from the list of databases
  2065. X *           he has, or to create a new database.
  2066. X */
  2067. Xchar *
  2068. Xselect_db()
  2069. X{
  2070. X    char dbname[MAXPATHLEN];
  2071. X    char *dblist[MAXDBFILES];
  2072. X    register int ndbs, i, row, col, spread;
  2073. X
  2074. X    /*
  2075. X     * Load the list of databases the user has.
  2076. X     */
  2077. X    ndbs = load_dblist(dblist);
  2078. X    spread = (ndbs + 3) / 4;
  2079. X
  2080. X    /*
  2081. X     * Set tty modes, clear screen.
  2082. X     */
  2083. X    set_modes();
  2084. X    clear();
  2085. X
  2086. X    /*
  2087. X     * Print the list of databases in four columns.
  2088. X     */
  2089. X    for (row = 0; row < spread; row++) {
  2090. X        for (col = 0; col < 4; col++) {
  2091. X            i = col * spread + row;
  2092. X
  2093. X            if (dblist[i])
  2094. X                mvaddstr(row, col * COLS/4, dblist[i]);
  2095. X        }
  2096. X    }
  2097. X
  2098. X    *dbname = '\0';
  2099. X
  2100. X    /*
  2101. X     * Prompt for the name of a database.
  2102. X     */
  2103. X    while (*dbname == '\0')
  2104. X        prompt_str(spread+2, 0, "Select a database: ", dbname);
  2105. X
  2106. X    /*
  2107. X     * If the database exists, return its name.
  2108. X     */
  2109. X    for (i = 0; i < ndbs; i++) {
  2110. X        if (!strcmp(dbname, dblist[i]))
  2111. X            return(savestr(dbname));
  2112. X    }
  2113. X
  2114. X    /*
  2115. X     * Doesn't exist - create it.
  2116. X     */
  2117. X    create_db(dbname);
  2118. X    return(savestr(dbname));
  2119. X}
  2120. X
  2121. X/*
  2122. X * load_dblist - load up a list of the databases the user has.
  2123. X */
  2124. Xload_dblist(dblist)
  2125. Xchar **dblist;
  2126. X{
  2127. X    DIR *dp;
  2128. X    int ndbs;
  2129. X    char *rindex();
  2130. X    register char *s;
  2131. X    extern int compare();
  2132. X    register struct direct *d;
  2133. X
  2134. X    ndbs = 0;
  2135. X
  2136. X    /*
  2137. X     * Open the database directory.
  2138. X     */
  2139. X    if ((dp = opendir(dbasedir)) == NULL) {
  2140. X        fprintf(stderr, "%s: cannot open \"%s\".\n", pname, dbasedir);
  2141. X        exit(1);
  2142. X    }
  2143. X
  2144. X    /*
  2145. X     * Read entries from the directory...
  2146. X     */
  2147. X    while ((d = readdir(dp)) != NULL) {
  2148. X        /*
  2149. X         * Search for a "." in the name, which marks
  2150. X         * the suffix.
  2151. X         */
  2152. X        if ((s = rindex(d->d_name, '.')) == NULL)
  2153. X            continue;
  2154. X
  2155. X        /*
  2156. X         * If this is an index definition file, save its
  2157. X         * name.
  2158. X         */
  2159. X        if (!strcmp(s, IDXFILE_SUFFIX)) {
  2160. X            if (ndbs < MAXDBFILES) {
  2161. X                *s = '\0';
  2162. X                dblist[ndbs++] = savestr(d->d_name);
  2163. X            }
  2164. X        }
  2165. X    }
  2166. X
  2167. X    /*
  2168. X     * Sort the list.
  2169. X     */
  2170. X    qsort(dblist, ndbs, sizeof(char *), compare);
  2171. X    closedir(dp);
  2172. X
  2173. X    return(ndbs);
  2174. X}
  2175. X
  2176. X/*
  2177. X * compare - comparis routine for qsort of dblist.
  2178. X */
  2179. Xstatic int
  2180. Xcompare(a, b)
  2181. Xchar **a, **b;
  2182. X{
  2183. X    return(strcmp(*a, *b));
  2184. X}
  2185. END_OF_FILE
  2186. if test 2630 -ne `wc -c <'selectdb.c'`; then
  2187.     echo shar: \"'selectdb.c'\" unpacked with wrong size!
  2188. fi
  2189. # end of 'selectdb.c'
  2190. fi
  2191. if test -f 'util.c' -a "${1}" != "-c" ; then 
  2192.   echo shar: Will not clobber existing file \"'util.c'\"
  2193. else
  2194. echo shar: Extracting \"'util.c'\" \(2490 characters\)
  2195. sed "s/^X//" >'util.c' <<'END_OF_FILE'
  2196. X#ifndef lint
  2197. Xstatic char *RCSid = "$Header: /u5/davy/progs/index/RCS/util.c,v 1.1 89/08/09 11:07:12 davy Exp $";
  2198. X#endif
  2199. X/*
  2200. X * util.c - utility routines for index program.
  2201. X *
  2202. X * David A. Curry
  2203. X * Research Institute for Advanced Computer Science
  2204. X * Mail Stop 230-5
  2205. X * NASA Ames Research Center
  2206. X * Moffett Field, CA 94035
  2207. X * davy@riacs.edu
  2208. X *
  2209. X * $Log:    util.c,v $
  2210. X * Revision 1.1  89/08/09  11:07:12  davy
  2211. X * Initial revision
  2212. X * 
  2213. X */
  2214. X#include <curses.h>
  2215. X#include <stdio.h>
  2216. X#include "defs.h"
  2217. X
  2218. X/*
  2219. X * set_dbase_dir - set the path to the database directory.
  2220. X */
  2221. Xset_dbase_dir()
  2222. X{
  2223. X    char *s;
  2224. X    char *getenv();
  2225. X
  2226. X    /*
  2227. X     * Look for it in the environment.
  2228. X     */
  2229. X    if ((s = getenv("INDEXDIR")) != NULL) {
  2230. X        strcpy(dbasedir, s);
  2231. X        return;
  2232. X    }
  2233. X
  2234. X    /*
  2235. X     * Otherwise, it's in the home directory.
  2236. X     */
  2237. X    if ((s = getenv("HOME")) == NULL) {
  2238. X        fprintf(stderr, "%s: cannot get home directory.\n", pname);
  2239. X        exit(1);
  2240. X    }
  2241. X
  2242. X    /*
  2243. X     * Make the name.
  2244. X     */
  2245. X    sprintf(dbasedir, "%s/%s", s, INDEXDIR);
  2246. X}
  2247. X
  2248. X/*
  2249. X * dbsort - comparison routine for qsort of database entries.
  2250. X */
  2251. Xdbsort(a, b)
  2252. Xstruct dbfile *a, *b;
  2253. X{
  2254. X    register int i, n;
  2255. X
  2256. X    /*
  2257. X     * Sort invalid entries to the end.
  2258. X     */
  2259. X    if ((a->db_flag & DB_VALID) == 0) {
  2260. X        if ((b->db_flag & DB_VALID) == 0)
  2261. X            return(0);
  2262. X
  2263. X        return(1);
  2264. X    }
  2265. X
  2266. X    if ((b->db_flag & DB_VALID) == 0)
  2267. X        return(-1);
  2268. X
  2269. X    /*
  2270. X     * Sort on first field, then try secondary fields.
  2271. X     */
  2272. X    n = 0;
  2273. X    for (i=0; (i < idx.idx_nlines) && (n == 0); i++)
  2274. X        n = strcmp(a->db_lines[i], b->db_lines[i]);
  2275. X    
  2276. X    return(n);
  2277. X}
  2278. X
  2279. X/*
  2280. X * error - reset tty modes and print an error message.
  2281. X */
  2282. Xerror(fmt, arg1, arg2, arg3)
  2283. Xchar *fmt, *arg1, *arg2, *arg3;
  2284. X{
  2285. X    reset_modes();
  2286. X
  2287. X    fprintf(stderr, fmt, arg1, arg2, arg3);
  2288. X}
  2289. X
  2290. X/*
  2291. X * savestr - save a string in dynamically allocated memory.
  2292. X */
  2293. Xchar *
  2294. Xsavestr(str)
  2295. Xchar *str;
  2296. X{
  2297. X    char *s;
  2298. X    char *malloc();
  2299. X
  2300. X    if ((s = malloc(strlen(str) + 1)) == NULL) {
  2301. X        reset_modes();
  2302. X
  2303. X        fprintf(stderr, "%s: out of memory.\n", pname);
  2304. X        exit(1);
  2305. X    }
  2306. X
  2307. X    strcpy(s, str);
  2308. X    return(s);
  2309. X}
  2310. X
  2311. X/*
  2312. X * byebye - exit.
  2313. X */
  2314. Xbyebye()
  2315. X{
  2316. X    register char c;
  2317. X    register int x, y;
  2318. X
  2319. X    /*
  2320. X     * If the database is modified, see if they really
  2321. X     * mean to exit without saving.
  2322. X     */
  2323. X    if (dbmodified) {
  2324. X        getyx(curscr, y, x);
  2325. X        c = prompt_char(y, 0,
  2326. X                "Really exit without saving? ",
  2327. X                "YyNn");
  2328. X
  2329. X        if ((c == 'n') || (c == 'N'))
  2330. X            return;
  2331. X    }
  2332. X
  2333. X    /*
  2334. X     * Reset tty modes and exit.
  2335. X     */
  2336. X    reset_modes();
  2337. X    exit(0);
  2338. X}
  2339. X
  2340. X/*
  2341. X * usage - print a usage message.
  2342. X */
  2343. Xusage()
  2344. X{
  2345. X    fprintf(stderr, "Usage: %s [-f filter] [-i] [database] [pattern]\n",
  2346. X        pname);
  2347. X    exit(1);
  2348. X}
  2349. END_OF_FILE
  2350. if test 2490 -ne `wc -c <'util.c'`; then
  2351.     echo shar: \"'util.c'\" unpacked with wrong size!
  2352. fi
  2353. # end of 'util.c'
  2354. fi
  2355. echo shar: End of archive 1 \(of 2\).
  2356. cp /dev/null ark1isdone
  2357. MISSING=""
  2358. for I in 1 2 ; do
  2359.     if test ! -f ark${I}isdone ; then
  2360.     MISSING="${MISSING} ${I}"
  2361.     fi
  2362. done
  2363. if test "${MISSING}" = "" ; then
  2364.     echo You have unpacked both archives.
  2365.     rm -f ark[1-9]isdone
  2366. else
  2367.     echo You still need to unpack the following archives:
  2368.     echo "        " ${MISSING}
  2369. fi
  2370. ##  End of shell archive.
  2371. exit 0
  2372.